#include <linux/uaccess.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kernel_stat.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <net/neighbour.h>
#include <net/arp.h>
#include <linux/if_arp.h>
#include <net/ip.h>
#include <net/netevent.h>
#include <linux/uaccess.h>
#include <linux/init.h>
#include <linux/kernel_stat.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include <net/neighbour.h>
#include <net/arp.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/errno.h>
#include <linux/fcntl.h>
#include <linux/in.h>

#include <asm/uaccess.h>
#include <asm/io.h>

#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/ethtool.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <linux/if_ether.h>	/* For the statistics structure. */
#include <linux/if_arp.h>	/* For ARPHRD_ETHER */
#include <linux/ip.h>
#include <linux/if.h>
#include <linux/tcp.h>
#include <linux/percpu.h>
#include <net/net_namespace.h>
#include <linux/u64_stats_sync.h>

/**
 *  sudo  arp-scan -I eth0  --localnet
 *   sudo  ifconfig
 *   sudo  ifconfig  -a
 *   sudo ifconfig eth0 down
 *   sudo ifconfig wlp1s0 down
 *   sudo ifconfig wlp1s0 up
 */

void testbit(struct net_device *netdev) {
	if (test_bit(__LINK_STATE_START, &netdev->state)) {
		pr_err("__LINK_STATE_START\n");
	}
	if (test_bit(__LINK_STATE_PRESENT, &netdev->state)) {
		pr_err("__LINK_STATE_PRESENT\n");
	}
	if (test_bit(__LINK_STATE_NOCARRIER, &netdev->state)) {
		pr_err("__LINK_STATE_NOCARRIER\n");
	}
	if (test_bit(__LINK_STATE_LINKWATCH_PENDING, &netdev->state)) {
		pr_err("__LINK_STATE_LINKWATCH_PENDING\n");
	}
	if (test_bit(__LINK_STATE_DORMANT, &netdev->state)) {
		pr_err("__LINK_STATE_DORMANT\n");
	}

}

int callback(struct notifier_block *nb, unsigned long msg, void *ptr) {
//	int ret;
	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
	pr_err("callback start\n");

	pr_err("netdevice_notifier allback,msg = %ld  \n", msg);
	pr_err("netdev->name= %s  \n", netdev->name);

	if (strcmp(netdev->name, "wlp1s0") == 0 && msg == NETDEV_UP) {
		pr_err("wlp1s0 netdev->state = %ld\n", netdev->state);
		pr_err("wlp1s0 netdev->flags = %d\n", netdev->flags);
//		testbit(netdev);
//		ret = dev_open(netdev);
//		if (ret < 0) {
//			pr_err("dev_open failed\n");
//			return ret;
//		}
//		pr_err("dev_close  success\n");
//		pr_err("netdev->state = %ld\n", netdev->state);
//			return 0;
	}

	if (strcmp(netdev->name, "eth0") == 0 && msg == NETDEV_UP) {
		pr_err("eth0 netdev->state = %ld\n", netdev->state);
		pr_err("eth0 netdev->flags = %d\n", netdev->flags);
//		testbit(netdev);

//		netdev_features_change(netdev);
//		pr_err("-------------\n");
//		return 0;
	}

//	switch (msg) {
//	case NETDEV_CHANGENAME:
//		pr_err("NETDEV_CHANGENAME\n");
//		break;
//	case NETDEV_UP:
//		pr_err("NETDEV_UP\n");
//		break;
//	case NETDEV_DOWN:
//		pr_err("NETDEV_DOWN\n");
//		break;
//	case NETDEV_REGISTER:
//		pr_err("NETDEV_REGISTER\n");
//		break;
//	case NETDEV_CHANGE:
//		pr_err("NETDEV_CHANGE\n");
//		break;
//	case NETDEV_FEAT_CHANGE:
//		pr_err("NETDEV_FEAT_CHANGE\n");
//		break;
//	default:
//		break;
//
//	}
	pr_err("-------------\n");
	return 0;
}

struct notifier_block nb;

inline int myinit(void) {
	nb.notifier_call = callback;
		register_netdevice_notifier(&nb);
	return 0;
}

static __init int my_init(void) {
	return myinit();
}

static void __exit my_exit(void) {
	unregister_netdevice_notifier(&nb);
}

module_init(my_init);
module_exit(my_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andy");
MODULE_DESCRIPTION("andy one-key driver");
MODULE_ALIAS("one-key");
